<?php

namespace app;
use app\PluginParse;
use app\core\Config;
use app\core\App;
use app\core\Log;

/**
 * 词库解释器
 */
class PluginAst
{
    use \app\core\Instance;
    /**
     * @var array 统计信息，包括成功和失败的计数
     */
    private $count = ['success' => 0, 'fail' => 0];

    /**
     * @var array 临时类列表缓存
     */
    private $classTempList = [];

    /**
     * @var array 最终类列表
     */
    public $classList = [];

    /**
     * @var array 插件配置
     */
    private $config = [];


    /**
     * @var bool 是否正在处理配置文件
     */
    private $remark = false;

    /**
     * 错误日志
     * @var array
     */
    public $error = [];

    /**
     * 临时缓存
     * @var array
     */
    private $temp = [];

    /**
     * 文件信息
     * @var array
     */
    public $fileInfo = [];

    /**
     * 加载和编译库文件
     */
    public function loadLibraries()
    {
        // 读取机器人配置
        $this->config = Config::get('app');
        // 读取词库列表
        $fileList = glob($this->config['dic_route'] . '/*.txt');
        foreach ($fileList as $dicPath) {
            $fileName = basename($dicPath);
            $fileId = md5($fileName);
            $this->classTempList[$fileId] = $fileName;
            $compiledSavePath = $this->config['cache_route'] . DIRECTORY_SEPARATOR . $this->prefix . $fileId . '.php';
            // 编译后的文件路径
            if ($this->isCompile($dicPath, $compiledSavePath)) {
                $this->fileInfo['path'] = $dicPath;
                $this->compileFile($dicPath, $compiledSavePath);
                $this->classList[$this->prefix . $fileId] = $fileName;
                $this->count['success']++;
                require_once $compiledSavePath;
            } else {
                $this->classList[$fileId] = $fileName;
                $this->count['success']++;
                require_once $compiledSavePath;
            }
        }

        $this->loadExt();

        //清除不必要的变量
        //$this->clearUnusedVariables();
    }

    /**
     * 加载词库扩展
     */
    public function loadExt()
    {

        $fileList = glob($this->config['ext_route'] . '/*.php');
        foreach ($fileList as $extPath) {
            require_once $extPath;
        }
    }



    /**
     * 判断文件是否需要编译
     *
     * @param string $dicSavePath 原文件路径
     * @param string $compiledSavePath 编译后的文件路径
     * @return bool 是否需要编译
     */
    private function isCompile($dicSavePath, $compiledSavePath)
    {
        if (!file_exists($compiledSavePath)) {
            return true;
        }
        if (!$this->config['compile_cache']) {
            $error = [
                'type' => 'Notice',
                'line' => 0,
                'path' => $dicSavePath,
                'message' => '未开启编译缓存，可能需要消化更多的资源',
            ];
            Log::log($error);
            return true;
        }
        return filemtime($compiledSavePath) <= filemtime($dicSavePath);
    }


    /**
     * 解析词库指令
     * @param string $dicPath 文件路径
     * @param string $compiledSavePath 编译后的文件路径
     * @return array|null 返回处理后的代码结构，如果没有有效的代码则返回null。
     */
    private function compileFile($dicPath, $compiledSavePath)
    {

        $dicText = file($dicPath);
        $instructionIndex = -1;
        $this->temp['instruction'] = false;
        $this->temp['classNameList'] = [];
        $codeList = [];
        $codeList['info'] = [
            'path' => $dicPath,
            'name' => basename($dicPath),
        ];
        foreach ($dicText as $key => $value) {
            // 移除行尾的换行符
            $value = rtrim($value, "\r\n");

            // 跳过以“&&”或“##”开头的行
            if (mb_substr($value, 0, 2) == "&&" || mb_substr($value, 0, 2) == "##") {
                continue;
            }

            if (mb_substr($value, 0, 1) == "@" && $key == 0) {
                $this->remark = true;
            }

            // 处理备注
            if ($this->remark) {
                preg_match('/^@(.*?):(.*?)$/', $value, $match);
                if (!empty($match)) {
                    $codeList['remark'][$match[1]] = $match[2];
                    continue;
                } else {
                    $this->remark = false;
                }
            }
            // 处理指令和代码片段
            if ($this->temp['instruction']) {
                if (empty(trim($value))) {
                    $this->temp['instruction'] = false;
                    // 如果当前指令下没有代码，则移除该指令
                    if (!isset($codeList['code'][$instructionIndex]['code'])) {
                        $error = [
                            'type' => 'Notice',
                            'line' => $key,
                            'path' => $codeList['info']['path'],
                            'message' => '无效的指令：' . $codeList['code'][$instructionIndex]['instruction'],

                        ];
                        Log::log($error);
                        unset($codeList['code'][$instructionIndex]);
                        $instructionIndex -= 1;
                    }
                } else {
                    $codeList['code'][$instructionIndex]['code'][] = $value;
                }
            } else if (!empty(trim($value))) {
                $methodName = $this->prefix . md5($value);
                if (isset($this->temp['classNameList'][$methodName])) {
                    $error = [
                        'type' => 'Warning',
                        'line' => $key + 1,
                        'path' => $codeList['info']['path'],
                        'message' => '指令重复定义：' . $value,

                    ];
                    Log::log($error);
                    //continue;
                }
                $instructionIndex += 1;
                $codeList['code'][$instructionIndex] = [
                    'type' => 'method',
                    'methodName' => $methodName,
                    'line' => $key + 1,
                    'instruction' => $value
                ];
                $this->temp['instruction'] = true;
                $this->temp['classNameList'][$methodName] = true;
            }

        }

        // 判断最后一条指令是否为空
        $endInstructionIndex = count($codeList['code']) - 1;
        if (!isset($codeList['code'][$endInstructionIndex]['code'])) {
            unset($codeList['code'][$endInstructionIndex]);
        }

        //判断解释器版本是否符合要求
        $version = App::_getVersion();
        if (isset($codeList['remark']['pluginVersion'])) {
            $codeList['remark']['pluginVersion'] = $this->completeVersion($codeList['remark']['pluginVersion']);
            if (!version_compare($version['plugin'], $codeList['remark']['pluginVersion'], '>=')) {
                $error = [
                    'type' => 'CompileError',
                    'line' => 0,
                    'path' => $codeList['info']['path'],
                    'message' => '解释器版本过低，请升级后重试！目标版本：' . $codeList['remark']['pluginVersion'] . '，当前版本：' . $version['plugin']
                ];
                Log::log($error);
                $this->count['fail']++;
                return;
            }

        } else {
            $error = [
                'type' => 'Notice',
                'line' => $key,
                'path' => $codeList['info']['path'],
                'message' => '未指定解释器最低版本号！',
            ];
            Log::log($error);
        }

        //是否引入扩展
        if (isset($codeList['remark']['extend'])) {
            $codeList['remark']['extend'] = explode(',', $codeList['remark']['extend']);
        }

        $handle = $this->codeHandle($codeList['code']);
        $this->arrayHandle($handle);
        //print_r($version);
        //解释代码
        $code = [
            'type' => 'class',
            //'path' => $codeList['info']['path'],
            'className' => $this->prefix . md5($codeList['info']['name']),
            'fileName' => $codeList['info']['name'],
            'remark' => isset($codeList['remark']) ? $codeList['remark'] : [],
            'code' => $handle,
        ];

        $dirPath = dirname($compiledSavePath);
        if (!is_dir($dirPath)) {
            mkdir($dirPath, 0777, true);
        }
        //dump($code);

        //print_r($code);
        file_put_contents($compiledSavePath, PluginParse::_toPhp($code));


    }


    /**
     * 解释代码
     *
     * @param array $codeArray 待处理的数组
     */
    private function codeHandle(&$codeArray)
    {
        $result = [];


        foreach ($codeArray as $key => $value) {
            $this->fileInfo['line'] = $value['line'];
            $codeArray[$key]['code'] = $this->processCode($value['code']);
        }


        //print_r($codeArray);



        return $codeArray;
    }


    /**
     * 初始化变量
     * @return void
     */
    private function setTemp()
    {

        $this->temp = [
            'ifSyntax' => false,//是否正在处理if语句
            'ifFatherSyntax' => false,//是否正在处理if语句(镶嵌语法)
            'ifSyntaxIndex' => 0,//if语句的索引指针
            'endIfSyntaxIndex' => false,//if语句的结束索引
            'elseIfSyntax' => false,//是否正在处理elseif语句
            'elseIfSyntaxIndex' => false,//elseif语句的索引指针
            'elseSyntax' => false,//是否正在处理else语句
            'jsonSyntax' => false,
            'funSyntax' => 0,
            'rawCode' => false,//输出原始字符串

        ];
    }


    /**
     * 处理每行代码
     */
    private function processCode(&$code)
    {
        //临时缓存
        $this->setTemp();

        $result = [];
        foreach ($code as $key => $value) {

            //if语句
            if (mb_substr($value, 0, 3) == '如果:' && !$this->temp['ifSyntax']) {
                $this->temp['ifSyntax'] = true;
                $this->temp['ifSyntaxIndex'] = $key;
                $result[$key] = [
                    'type' => 'if',
                    'cond' => ExpressionParser::_parse(mb_substr($value, 3))
                ];
                continue;
            }

            //if语句(镶嵌语法)
            if (mb_substr($value, 0, 3) == '如果:') {
                $result[$key] = [
                    'type' => 'if',
                    'cond' => ExpressionParser::_parse(mb_substr($value, 3)),
                    'index' => $this->temp['ifSyntaxIndex']
                ];
                //$this->temp['ifFatherSyntax'] = true;
                $this->temp['ifSyntaxIndex'] = $key;
                //停止处理else语句
                $this->temp['elseSyntax'] = false;
                continue;
            }

            //if语句结束
            if ($value == '返回' || $value == '如果尾') {

                if ($return = $this->returnExprHandle($value, $key, $code)) {

                    $this->isifSyntax($result, $key, $return);
                }

                //if语句结束
                if ($this->temp['endIfSyntaxIndex']) {
                    $this->setTemp();
                }
                continue;
            }

            //设置变量
            if (preg_match('/([^:]+):/', mb_substr($value, 0, 2), $match)) {

                $varCode = $this->splitString(mb_substr($value, 2));
                $this->isifSyntax($result, $key, [
                    'type' => 'setVar',
                    'varName' => 'Var_' . md5($match[1]),
                    'code' => $varCode
                ]);
                continue;
            }

            //goto标签
            if (preg_match('/^:(([^:])+)/', $value, $match)) {
                $this->isifSyntax($result, $key, [
                    'type' => 'label',
                    'labelName' => $this->getLabelName($match[1]),
                ]);
                continue;
            }

            //读取变量
            if (preg_match('/^%(.*?)%$/', $value, $match)) {
                $this->isifSyntax($result, $key, $this->varExprHandle($value));
                continue;
            }

            //调用函数(单独成行)
            if (preg_match('/^\\$(.*)\\$$/', $value, $match) && mb_substr_count($value, '$') == 2) {
                $this->isifSyntax($result, $key, $this->funExprHandle($value));
                continue;
            }

            //json语法
            if (preg_match('/^json:(([^:])+)/', $value, $match)) {
                $this->temp['jsonSyntax'] = true;
                $this->isifSyntax($result, $key, [
                    'type' => 'json',
                    'code' => $this->splitString(mb_substr($value, 5)),
                ]);
                $this->temp['jsonSyntax'] = false;

                continue;
            }

            if (!empty($value)) {
                $this->temp['rawCode'] = true;
                //字符串
                $this->isifSyntax($result, $key, [
                    'type' => 'string',
                    'code' => $this->splitString($value)
                ]);
            }
        }

        return $result;

        /* if (is_array($value)) {
            $value = implode("\n", $value);
        }
        // 去除前后空格
        $value = trim($value);
        // 如果当前行为"返回"且不在条件语句中，则结束处理
        if ($value == "返回" && !$this->_condition) {
            $code[$k]['code'][$key]['type'] = 'return';
            return;
        }
        // 如果当前行为"如果尾"，且当前不在条件语句中，则结束处理
        if ($value == "如果尾") {
            //            $code[$k]['code'][$this->_key]['code']['elseif'] = [];
            $this->_codeBlock = "elseif";
            $this->_keys++;
            return;
        }
        // 处理条件语句
        if (mb_substr($value, 0, 3) == '如果:' && !$this->_condition) {
            $code[$k]['code'][$key]['type'] = 'condition';
            $code[$k]['code'][$key]['cond'] = $value;
            $this->_condition = true;
            $this->_key = $key;
            $this->_codeBlock = "if";


            $code[$k]['code'][$this->_key]['code']['if'] = [];
            $code[$k]['code'][$this->_key]['code']['elseif'] = [];
            $code[$k]['code'][$this->_key]['code']['else'] = [];

            return;
        }
        // 处理条件语句中的代码块或普通行代码
        if ($this->_condition) {
            if ($this->_codeBlock == 'if') {
                $code[$k]['code'][$this->_key]['code']['if'][] = $value;
            } else if ($this->_codeBlock == 'elseif') {
                $code[$k]['code'][$this->_key]['code']['elseif'][$this->_keys][] = $value;
            } else {
                $code[$k]['code'][$this->_key]['code']['else'][] = $value;
            }
        } else {
            //解析XML
            if (mb_substr($value, 0, 5) == 'card:') {
                $code[$k]['code'][$key]['type'] = 'card';
                $this->continuity_key = $key;
                $this->continuity = true;
                return;
            }
            //解析JSON
            if (mb_substr($value, 0, 5) == 'json:') {
                if (mb_substr($value, 0, 5) == 'json:') {
                    $code[$k]['code'][$key]['type'] = 'json';
                    $code[$k]['code'][$key]['code'][] = mb_substr($value, 5);
                } else {
                    $code[$k]['code'][$key]['type'] = 'json';
                    $this->continuity_key = $key;
                    $this->continuity = true;
                }
                return;
            }
            //解析变量
            if (preg_match('/(.*):/', mb_substr($value, 0, 2), $match)) {
                $code[$k]['code'][$key]['type'] = 'var';
                $code[$k]['code'][$key]['name'] = $match[1];
                //解析函数
                $fun_value = mb_substr($value, 2);
                if (preg_match_all('/\\$(.*?)\\$/', $fun_value, $match)) {
                    $numsss = 0;
                    foreach ($match[0] as $keys => $values) {
                        $code[$k]['code'][$key]['code'][$numsss]['type'] = 'fun';
                        $code[$k]['code'][$key]['code'][$numsss]['code'][] = $values;
                        $numsss++;
                        $fun_value = str_replace($values, '', $fun_value);
                    }
                    if (!empty(trim($fun_value))) {
                        $code[$k]['code'][$key]['code'][$numsss] = $fun_value;
                    }
                } else {
                    $code[$k]['code'][$key]['code'][] = mb_substr($value, 2);
                }
                return;
            }
            //解析函数
            if (preg_match('/^\\$(.*)\\$$/', $value)) {
                $code[$k]['code'][$key]['type'] = 'fun';
                $code[$k]['code'][$key]['code'][] = $value;
                return;
            }
            //解析函数
            if (preg_match_all('/\\$(.*?)\\$/', $value, $match)) {
                $numsss = 0;
                foreach ($match[0] as $keys => $values) {
                    $code[$k]['code'][$key]['code'][$numsss]['type'] = 'fun';
                    $code[$k]['code'][$key]['code'][$numsss]['code'][] = $values;
                    $numsss++;
                    $value = str_replace($values, '', $value);
                }
                //                $code[$k]['code'][$key]['type'] = 'fun';
                if (!empty(trim($value))) {
                    $code[$k]['code'][$key]['code'][$numsss]['type'] = 'string';
                    $code[$k]['code'][$key]['code'][$numsss]['code'][] = $value;
                }
                return;
            }

            if ($this->continuity) {
                $code[$k]['code'][$this->continuity_key]['code'][] = $value;
            } else {
                $code[$k]['code'][$key]['type'] = 'string';
                $code[$k]['code'][$key]['code'][] = $value;
            }
            //        $this->Grammar($code[$k]['code'],$value);
        } */
    }



    /**
     * 是否是if语句
     * @return void
     */
    private function isifSyntax(&$result, $key, $array)
    {

        if ($this->temp['elseSyntax']) {
            $result[$this->temp['ifSyntaxIndex']]['code']['else'][] = $array;
        } else if ($this->temp['elseIfSyntax']) {
            $result[$this->temp['ifSyntaxIndex']]['code']['elseif'][$this->temp['elseIfSyntaxIndex']][] = $array;
        } else if ($this->temp['ifSyntax']) {
            $result[$this->temp['ifSyntaxIndex']]['code']['if'][] = $array;
        } else {
            $result[$key] = $array;

        }
    }



    /**
     * 处理函数调用
     */
    private function funExprHandle($value)
    {



        $result = [];

        //不处理
        if (preg_match('/\{([^\]]+)\}/', $value, $key) && !$this->temp['jsonSyntax']) {
            return $key[1];

        }

        if (preg_match('/^\\$jump :(.*?)\\$$/', $value, $match) && mb_substr_count($value, '$') == 2) {
            return [
                'type' => 'goto',
                'labelName' => $this->getLabelName($match[1]),
            ];
        }


        //调用函数(单独成行)
        if (preg_match('/^\\$(.*)\\$$/', $value, $match) && mb_substr_count($value, '$') == 2) {
            $args = explode(' ', $match[1]);
            $funArgs = [];
            $funName = $args[0];
            array_shift($args);
            $this->temp['rawCode'] = false;
            foreach ($args as $key => $values) {
                $funArgs[] = $this->splitString($values);
            }
            return [
                'type' => 'fun',
                'funName' => 'Fun_' . md5($funName),
                'rowName' => $funName,
                'funArgs' => $funArgs,
                //'code' => $match[1]
            ];
        }

        //调用函数(字符串)
        if (preg_match_all('/\\$(.*?)\\$/', $value, $match)) {
            $this->temp['funExpr'] = 0;
            $result['type'] = 'fun';
            foreach ($match[0] as $values) {
                $result['code'][$this->temp['funExpr']] = $values;
                $this->temp['funExpr']++;
            }
            return $result;

        }

        return $this->varExprHandle($value);
    }

    /**
     * 处理变量调用
     * @param mixed $value
     * @return array
     */
    private function varExprHandle($value)
    {

        //调用变量(单独成行)
        if (preg_match('/^%(.*?)%$/', $value, $match)) {
            if (!isset($this->config['var'])) {
                $this->config = Config::get('app');
            }

            //print_r($this);

            //print_r($this);

            foreach ($this->config['var'] as $var) {
                if (preg_match('/^' . $var . '(.*)/', $match[1], $parms)) {
                    $this->temp['rawCode'] = false;
                    if (!empty($parms[1])) {
                        $funArgs = [$this->splitString($parms[1])];
                    } else {
                        $funArgs = [];
                    }
                    return [
                        'type' => 'fun',
                        'funName' => 'Fun_' . md5($var),
                        'rowName' => $var,
                        'funArgs' => $funArgs,
                        //'code' => $match[1]
                    ];
                }
            }
            return [
                'type' => 'var',
                'varName' => 'Var_' . md5($match[1]),
            ];
        }


        return $this->systemExprHandle($value);
    }

    private function systemExprHandle($value)
    {
        if (preg_match('/±(\w*)=(.*?)±/', $value, $match)) {
            $this->temp['rawCode'] = false;
            //print_r($match[2]);
            $funArgs = [$this->splitString($match[2])];
            print_r($funArgs);
            //print_r($match);
            return [
                'type' => 'fun',
                'funName' => 'Fun_' . md5($match[1]),
                'rowName' => $match[1],
                'funArgs' => $funArgs,
                //'code' => $match[1]
            ];

        }
        return $this->mathsExprHandle($value);
        //return 'label_' . md5($name);
    }

    private function mathsExprHandle($value)
    {

        if (preg_match('/^\[(?:[0-9]*[a-zA-Z]*)?[+\-^%\/*](?:[0-9a-zA-Z]*[+\-^%\/*]*)*\]$/', $value, $match)) {
            //print_r($match);
            return [
                'type' => 'maths',
                'code' => $this->splitString(substr($value, 1, -1)),
            ];

        }
        return $this->arrayExprHandle($value);

    }











    private function arrayExprHandle($value)
    {

        $result = [];

        //调用变量(单独成行)
        if (preg_match_all('/^@(.*?)(\[[^\]]+\])+$/', $value, $match)) {
            preg_match_all('/\[([^\]]+)\]/', $value, $key);
            $this->temp['rawCode'] = false;
            foreach ($key[1] as $keys => $values) {
                $result[] = $this->funExprHandle($values);
            }
            return [
                'type' => 'array',
                'varName' => 'Var_' . md5($match[1][0]),
                'key' => $result
            ];
        }

        //输出字符串
        if (isset($this->temp['rawCode']) && $this->temp['rawCode']) {
            //echo "要求原始输出;".$value."\n";
            $this->temp['rawCode'] = false;
            return $value;
        } else {
            return [
                'type' => 'string',
                'code' => $value
            ];
        }

    }

    /**
     * 处理返回语句
     * @param mixed $value
     * @param mixed $key
     * @param mixed $code
     * @return bool|string[]
     */
    private function returnExprHandle($value, $key, &$code)
    {

        if ($value == '返回') {
            if (isset($code[$key + 1]) && $code[$key + 1] == '如果尾') {
                $this->temp['endIfSyntaxIndex'] = true;
                //停止处理else语句
                $this->temp['elseSyntax'] = false;
                return [
                    'type' => 'return',
                    'code' => 'return'
                ];

            }
            //$this->temp['ifFatherSyntax'] = false;
            //开始处理else语句
            $this->temp['elseSyntax'] = true;
            //$this->temp['elseIfSyntax'] = true;
            //$this->temp['elseIfSyntaxIndex'] = $key;

        }
        if ($value == '如果尾') {
            if ($code[$key - 1] != '返回') {
                //退出if语句
                $this->setTemp();
                return false;

            }

        }


        return false;


    }

    private function arrayHandle(&$code)
    {
        $result = [];
        foreach ($code as $key => $value) {
            $result = array_reverse($value['code'], true);
            foreach ($result as $keys => $values) {

                //镶嵌if
                if ($values['type'] == 'if' && isset($values['index'])) {

                    //echo "当前节点：{$keys},父节点；" . $this->getFatherIndex($code, $key, $values);
                    $ifFatherIndex = $this->getFatherIndex($code, $key, $values);
                    //$ifFatherIndex = $values['index'];
                    //print_r($code[$key]['code'][$values['index']]['code']);

                    //elseif节点不存在
                    if (!isset($code[$key]['code'][$values['index']]['code']['elseif'])) {
                        $code[$key]['code'][$ifFatherIndex]['code']['elseif'] = [];
                    }

                    //子节点存在else节点，移动到父else节点
                    if (isset($code[$key]['code'][$keys]['code']['else'])) {
                        $code[$key]['code'][$ifFatherIndex]['code']['else'] = $code[$key]['code'][$keys]['code']['else'];
                        unset($code[$key]['code'][$keys]['code']['else']);

                    }
                    array_push($code[$key]['code'][$ifFatherIndex]['code']['elseif'], $code[$key]['code'][$keys]);
                    //$code[$key]['code'][$values['index']]['code'][] = $values['code'];
                    unset($code[$key]['code'][$keys]);

                }
            }
            //print_r($value);
            //print_r($result);


        }



    }


    /**
     * 获取if父id
     * @param mixed $code
     * @param mixed $key
     * @param mixed $values
     * @return mixed
     */
    private function getFatherIndex(&$code, $key, $values)
    {
        //print_r($values);

        //存在父节点
        if (isset($code[$key]['code'][$values['index']]['index'])) {

            return $this->getFatherIndex($code, $key, $code[$key]['code'][$values['index']]);
        }
        return $values['index'];

    }



    /**
     * 分词器
     * @param mixed $input
     * @return mixed
     */
    public function splitString($input)
    {
        $input = trim($input);
        // 使用正则表达式匹配 % 和 $ 包裹的内容，以及 @x[x]+ 模式
        //$stringNum = preg_match_all('/{[^{]*}|%[^%]*%|\$[^\$]*\$|@\w+(\[\w*\])+|±\w+( |=).*?±|[^%\$@]+/', $input, $matches);
        $stringNum = preg_match_all('/{[^{]*}|\[[^\]]*\]|%[^%]*%|\$[^\$]*\$|@\w*(\[\w*\])+|±\w*( |=).*?±|[^%{}\[\]]+/', $input, $matches);

        if ($stringNum <= 1) {

            return $this->funExprHandle($matches[0][0]);
        }
        $result = [];
        $this->temp['rawCode'] = false;

        //print_r($matches);
        foreach ($matches[0] as $key => $value) {
            $result[] = $this->funExprHandle($value);
        }

        return [
            'type' => 'concat',
            'code' => $result,
        ];
    }


    /**
     * 清除不必要的变量
     */
    private function clearUnusedVariables()
    {
        unset(
            $this->config,//配置信息
            $this->temp//临时缓存
        );
    }



    /**
     * 获取goto标签名称
     * @param mixed $input
     * @return string
     */
    private function getLabelName($input)
    {
        $md5Hash = md5($input);

        $result = '';

        for ($i = 0; $i < strlen($md5Hash); $i++) {
            $char = $md5Hash[$i];

            if (!is_numeric($char)) {
                $result .= $char;
            }

            if (strlen($result) == 5) {
                break;
            }
        }

        return $result;
    }



    /**
     * 版本号补全
     * @param mixed $version
     * @return string
     */
    private function completeVersion($version)
    {
        $parts = explode('.', $version);

        while (count($parts) < 3) {
            $parts[] = '0';
        }

        return implode('.', $parts);
    }

}



class ExpressionParser
{

    use \app\core\Instance;
    private $expression;

    /**
     * ExpressionParser 构造函数
     *
     * @param string $expression 需要解析的逻辑表达式。
     */
    public function __construct($expression = '')
    {
        $this->expression = $expression;
    }


    /**
     * 解析表达式并生成 AST。
     *
     * @param string $expression 需要解析的逻辑表达式。如果未提供，将使用默认表达式。
     * @return array 生成的抽象语法树。
     */
    public function parse($expression = '')
    {
        // 如果提供了新的表达式，则更新实例中的表达式
        if ($expression !== '') {
            $expression = str_replace(['&', '|'], ['&&', '||'], $expression);
            $expression = str_replace(['&&&&', '||||'], ['&&', '||'], $expression);
            //$expression = str_replace(' ', '', $expression);
            if (preg_match_all('/([!=]+)([|&]+)/', $expression, $match)) {
                foreach ($match[0] as $key => $value) {
                    $info = debug_backtrace()[4]['object']->fileInfo;
                    $error = [
                        'type' => 'Warning',
                        'line' => $info['line'],
                        'path' => $info['path'],
                        'message' => '不推荐的写法：' . $value
        
                    ];
                    Log::log($error);
                    $expression = str_replace($value, $match[1][$key] . 'null' . $match[2][$key], $expression);
                }

            }
            //echo "条件语句" . $expression;
            $this->expression = $expression;
        }

        $tokens = $this->tokenize($this->expression);
        $ast = $this->parseExpression($tokens);
        //print_r($ast);
        return $ast;
    }

    private function tokenize($expression)
    {
        $tokens = [];
        $pattern = '/(\d+|==|!=|>=|<=|&&|>|<|\|\||\(|\)|[^=!><|&]+)/';
        preg_match_all($pattern, $expression, $matches);
        foreach ($matches[0] as $match) {
            if (trim($match) !== '') {
                $tokens[] = $match;
            }
        }
        //print_r($tokens);
        return $tokens;
    }

    private function parseExpression(&$tokens)
    {
        $left = $this->parseTerm($tokens);

        while (isset($tokens[0]) && $tokens[0] === '&&') {
            array_shift($tokens);
            $right = $this->parseTerm($tokens);
            $left = ['type' => 'binary', 'operator' => '&&', 'left' => $left, 'right' => $right];
        }

        return $left;
    }

    private function parseTerm(&$tokens)
    {
        $left = $this->parseFactor($tokens);

        while (isset($tokens[0]) && $tokens[0] === '||') {
            array_shift($tokens);
            $right = $this->parseFactor($tokens);
            $left = ['type' => 'binary', 'operator' => '||', 'left' => $left, 'right' => $right];
        }

        return $left;
    }

    private function parseFactor(&$tokens)
    {
        $token = array_shift($tokens);

        if ($token === '(') {
            $expression = $this->parseExpression($tokens);
            array_shift($tokens); // Remove ')'
            return $expression;
        }

        return $this->parseComparison($token, $tokens);
    }

    private function parseComparison($left, &$tokens)
    {
        $operator = array_shift($tokens);
        $right = array_shift($tokens);

        return [
            'type' => 'comparison',
            'operator' => $operator,
            'left' => PluginAst::_splitString($left),
            'right' => PluginAst::_splitString($right)
        ];
    }
}

